import { ClassName, Events } from "./Constants";
import GridSystem from "./GridSystem";
import { IPixelPos } from "./Interface";
import { Utils } from "./utils"

interface ViewRect {
    x: number,
    y: number,
    width: number,
    height: number,
}

let fn = () => { }
let dragViewRect = (e: any) => { }

// 小地图
class MiniMap extends GridSystem {
    className = ClassName.MINIMAP
    viewRect: ViewRect;  // 当前显示的区域
    isDraging: boolean;  // 是否正在渲染中
    glInstance: GridSystem;  // 主页面gls实例
    lastMove: IPixelPos = { x: 0, y: 0 };
    ratio = 1;

    constructor(gls: GridSystem, width = 350, height = 0) {
        const ratio = gls.domElement.height / gls.domElement.width;
        const canvasDom = document.createElement("canvas");
        canvasDom.style.position = "absolute";
        canvasDom.style.left = "0px";
        canvasDom.style.top = "0px";
        canvasDom.id = ClassName.MINIMAP;
        canvasDom.style.border = `1px solid #ccc`
        canvasDom.style.background = "#fff"
        canvasDom.style.zIndex = gls.domElement.style.zIndex + 10
        canvasDom.width = width;
        canvasDom.height = height || width * ratio;
        const parentNode = gls.domElement.parentNode as HTMLElement;
        parentNode.appendChild(canvasDom);
        super(canvasDom, false);
        this.glInstance = gls;
        this.ratio = ratio
        this.viewRect = { x: 0, y: 0, width: 0, height: 0 }
        this.isDraging = false;
        this.pageSlicePos = {
            x: this.domElement.width / 2,
            y: this.domElement.height / 2
        };
        this.scale = 1;
        fn = this.setViewRect.bind(this);
        fn();
        this.glInstance.on(Events.TRANSLATE, fn)
        this.glInstance.on(Events.ZOOM, fn)
    }

    override initEventListener() {  // 重写
        dragViewRect = (e: any) => { this.dragViewRect(e) }
        if (GridSystem.isMobile) {
            this.domElement.addEventListener(Events.TOUCHSTART, dragViewRect)
        } else {
            this.domElement.addEventListener(Events.MOUSE_DOWN, dragViewRect)
        }
        this.domElement.addEventListener(Events.CONTEXTMENU, (e) => e.preventDefault());
    }

    override draw() {
        this.ctx.clearRect(0, 0, this.domElement.width, this.domElement.height);
        this.ctx.fillStyle = this.background;
        this.ctx.fillRect(0, 0, this.domElement.width, this.domElement.height);
        const features = this.glInstance.features.filter(f => Utils.isBasicFeature(f));
        this.drawFeatures(features);  // 绘制所有元素
        // 绘制当前显示区域的矩形框
        this.ctx.fillStyle = "rgba(255,251,143,.5)"
        this.ctx.fillRect(this.viewRect.x, this.viewRect.y, this.viewRect.width, this.viewRect.height)
    }

    setViewRect() {
        // 主页面区域总宽高
        // 跟新小地图可视框
        this.viewRect.width = this.glInstance.domElement.width / this.glInstance.scale * this.scale
        this.viewRect.height = this.viewRect.width * this.ratio
        this.viewRect.x = this.pageSlicePos.x - this.glInstance.pageSlicePos.x / this.glInstance.scale * this.scale
        this.viewRect.y = this.pageSlicePos.y - this.glInstance.pageSlicePos.y / this.glInstance.scale * this.scale
    }

    dragViewRect(e: any) {
        this.dispatch(new CustomEvent(Events.MOUSE_DOWN, { detail: e }))
        const { x, y } = Utils.getMousePos(this.domElement, e)
        this.lastMove = { x, y };
        if (x > this.viewRect.x && x < this.viewRect.x + this.viewRect.width && y > this.viewRect.y && y < this.viewRect.y + this.viewRect.height) {  // 鼠标在矩形框内
            this.isDraging = true;
            const mousemove = (ev: any) => {
                this.dispatch(new CustomEvent(Events.DRAG, { detail: ev }))
                this.domElement.style.cursor = "move"
                const { x: x1, y: y1 } = Utils.getMousePos(this.domElement, ev);
                if (this.lastMove.x && this.lastMove.y) {
                    const dx = (x1 - this.lastMove.x);
                    const dy = (y1 - this.lastMove.y);
                    this.viewRect.x += dx * this.scale
                    this.viewRect.y += dy * this.scale
                    this.glInstance.translate(-dx * this.glInstance.scale, -dy * this.glInstance.scale)
                }
                this.lastMove = { x: x1, y: y1 };
            }  
            const mouseup = (ev: any) => {
                this.domElement.style.cursor = "default"
                this.isDraging = false;
                this.dispatch(new CustomEvent(Events.MOUSE_UP, { detail: ev }))
                document.removeEventListener(Events.MOUSE_MOVE, mousemove)
                document.removeEventListener(Events.MOUSE_UP, mouseup)
                document.removeEventListener(Events.TOUCHMOVE, mousemove)
                document.removeEventListener(Events.TOUCHEND, mouseup)
            }
            if (GridSystem.isMobile) {
                document.addEventListener(Events.TOUCHMOVE, mousemove, { passive: false })
                document.addEventListener(Events.TOUCHEND, mouseup)
            } else {
                document.addEventListener(Events.MOUSE_MOVE, mousemove)
                document.addEventListener(Events.MOUSE_UP, mouseup)
            }
        } else {
            this.domElement.style.cursor = "default";
        }
    }

    destroy() {
        const parentNode = this.glInstance.domElement.parentNode as HTMLElement;
        parentNode.removeChild(this.domElement)
        this.glInstance.off(Events.TRANSLATE, fn)
        this.glInstance.off(Events.ZOOM, fn)
        this.domElement.removeEventListener(Events.MOUSE_DOWN, dragViewRect)
        this.domElement.removeEventListener(Events.TOUCHSTART, dragViewRect)
    }

}

export default MiniMap;
